package edu.auctionmart

import grails.converters.JSON
import org.joda.time.DateTime

class AuctionController {

	def authenticateService
	def auctionService
	def scheduleAlertService
	def queueService
	def ivrService
	def emailService
	def smsService

	static navigation = [
		[group: 'tabs', action: 'create', title: 'Sell', order: 1],
		[action: 'list', title: 'Auctions', order: 2]
	]

	def index() {
		redirect(action: list)
	}

	def show = {
		def view = "showWeb"

		withMobileDevice {
			def device ->
			println device
			view = "showMobile"
		}

		def auction = Auction.get(params.id)
		if (!auction) {
			flash.message = "Auction not found with id $params.id"
			redirect action: list
			return
		}
		render (view: view, model: [auctionInstance: auction])
	}

	def create = {
		def view = "createWeb"
		withMobileDevice {
			def device ->
			println device
			view = "createMobile"
		}
		render (view: view, model: [auctionInstance: new AuctionCreateCommand()])
	}

	def list = {
		def view = "listWeb"

		withMobileDevice {
			def device ->
			println device
			view = "listMobile"
		}

		def auctionList = Auction.findAll()
		render (view: view, model: [auctionInstanceList: auctionList])
	}

	def listJson = {

		def auctionList = Auction.findAll {status == "OnGoing" }
		render auctionList as JSON

	}

	def bid = {
		def view = "showWeb"

		withMobileDevice {
			def device ->
			println device
			view = "showMobile"
		}

		Auction theAuction = Auction.get(params.id)
		DateTime bidTime = DateTime.now()
		if (theAuction.endTime > bidTime) {
			float maxBid = Float.valueOf(params.maxBid)

			def principal = authenticateService.principal()
			String userName = principal.getUsername()
			def userInstance = User.findByUsername(userName)

			if (theAuction.getSeller().getUsername().equals(userName)) {
				flash.message = "You may not bid on your own auction."
				render view: view, model: [auctionInstance: theAuction]
				return
			} else {

				if (theAuction.currentBid == null && maxBid >= theAuction.startBid) {
					Bid theBid = new Bid(auction: theAuction, userAccount: userInstance, amount: maxBid, time: bidTime)
					theAuction.addToBids(theBid)
					theBid.save()
					Bid currentBid = new Bid(auction: theAuction, userAccount: userInstance, amount: theAuction.startBid, time: bidTime)
					theAuction.currentBid = currentBid
					currentBid.save()
					theAuction.save()
					flash.message = "Congratulations, you are the new high bidder."
					render view: view, model: [auctionInstance: theAuction]
				} else if (maxBid > theAuction.currentBid.getAmount()) {
					ArrayList<Bid> listOfBids = new ArrayList<Bid>(theAuction.getBids());
					Collections.sort(listOfBids)
					if (theAuction.getCurrentBid().getUserAccount().getUsername().equals(userName)) {
						//that user is already winning, so the last bid in the list is theirs
						Bid highestBid = listOfBids.get(listOfBids.size() - 1)
						highestBid.setAmount(maxBid)
						highestBid.save()
						flash.message = "You were already winning, but we've changed your maximum bid to " + maxBid + " dollars"
						render view: view, model: [auctionInstance: theAuction]
					} else {
						//compare highest bid vs this bid
						Bid highestBid = listOfBids.get(listOfBids.size() - 1)
						Bid theNewBid = new Bid(auction: theAuction, userAccount: userInstance, amount: maxBid, time: bidTime)
						theAuction.addToBids(theNewBid)

						if (highestBid.getAmount() >= theNewBid.getAmount()) {
							//current bid should be changed in its value
							theAuction.currentBid.setAmount(theNewBid.getAmount())
							theAuction.save()
							flash.message = "Your bid was not high enough, sorry."
							render view: view, model: [auctionInstance: theAuction]
						} else {
							//1 cent higher, new user
							float value = highestBid.getAmount() + 0.01
							theAuction.currentBid.setAmount(value)
							theAuction.currentBid.setUserAccount(theNewBid.getUserAccount())
							theAuction.save()
							flash.message = "Congratulations, you are the new high bidder."
							render view: view, model: [auctionInstance: theAuction]
						}
					}
				} else {
					//don't allow, not higher than current bid
					flash.message = "Your bid is below the current bid."
					render view: view, model: [auctionInstance: theAuction]
				}
			}
		} else {
			flash.message = "The auction has ended, your bid was not placed."
			render view: view, model: [auctionInstance: theAuction]
		}

	}



	def reminder = { AlertTimeCommand atc ->

		def view = "showWeb"

		withMobileDevice {
			def device ->
			println device
			view = "showMobile"
		}

		DateTime reminderTime = atc.alertTime
		def principal = authenticateService.principal()
		String userName = principal.getUsername()

		Auction theAuction =  Auction.get(params.id)
		String type = params.type
		DateTime now = DateTime.now()
		println("now: " + now)
		println("reminder time: " + reminderTime)
		println("auction end time: " + theAuction.getEndTime())
		println("auction start time: " + theAuction.getStartTime())

		//		if (reminderTime >= theAuction.getEndTime()) {
		//			//do nothing, auction is over
		//			flash.message = "Cannot schedule alert after auction end."
		//			render view: 'show', model: [auctionInstance: theAuction]
		//		} else
		if (reminderTime <= theAuction.getStartTime()) {
			//Don't schedule alerts before the start of an auction
			flash.message = "Cannot schedule alert before an auction."
			render view: view, model: [auctionInstance: theAuction]
		} else if (reminderTime <= now) {
			//Don't schedule alerts in the past
			flash.message = "Cannot schedule alert in the past."
			render view: view, model: [auctionInstance: theAuction]
		} else {
			//Schedule the alert

			if (type.equals("EMAIL")) {
				scheduleAlertService.scheduleAlertJob(reminderTime, theAuction.auctionTitle, userName, AlertType.EMAIL, emailService, queueService)
				println("E-mail alert scheduled")
				flash.message = "Your alert has been scheduled."
				render view: view, model: [auctionInstance: theAuction]
			} else if (type.equals("SMS")) {
				scheduleAlertService.scheduleAlertJob(reminderTime, theAuction.auctionTitle, userName, AlertType.SMS, smsService, queueService)
				println("SMS alert scheduled")
				flash.message = "Your alert has been scheduled."
				render view: view, model: [auctionInstance: theAuction]
			} else if (type.equals("IVR")) {
				scheduleAlertService.scheduleAlertJob(reminderTime, theAuction.auctionTitle, userName, AlertType.IVR, ivrService, queueService)
				println("IVR alert scheduled")
				flash.message = "Your alert has been scheduled."
				render view: view, model: [auctionInstance: theAuction]
			}
		}
	}


	def save = {AuctionCreateCommand acc ->

		def view = "createWeb"

		withMobileDevice {
			def device ->
			println device
			view = "createMobile"
		}

		if (acc.hasErrors()) {
			render view: view, model: [auctionInstance: acc]
		}
		else {

			def principal = authenticateService.principal()
			String userName = principal.getUsername()
			def userInstance = User.findByUsername(userName)

			def auction = new Auction(acc.properties)
			auction.setSeller(userInstance)
			auction.item = new Item(acc.properties)
			auction.status = AuctionStatus.OnGoing

			if (auction.save()) {
				flash.message = "Successfully created Auction ${auction.auctionTitle}"
				//redirect action: create, id: auction.id
				scheduleAlertService.scheduleAlertJob(auction.endTime, auction.auctionTitle, userName, AlertType.EMAIL, emailService, queueService)
				scheduleAlertService.scheduleAlertJob(auction.endTime, auction.auctionTitle, "admin", AlertType.EMAIL, emailService, queueService)

				withMobileDevice {
					def device ->
					println device
					view = "showMobile"
				}

				render view: view, model: [auctionInstance: acc]
			} else {
				render view: view, model: [auctionInstance: acc]
			}
		}
	}

	class AlertTimeCommand {
		DateTime alertTime

	}

	class AuctionCreateCommand {

		String auctionTitle
		DateTime startTime = new DateTime()
		DateTime endTime
		float startBid
		Float hiddenMinBid

		String name
		String description
		ItemCategory category
		List<Byte> image
		String isbn
		Float weight
		String dimension
		int quantity


		static constraints = {
			auctionTitle(nullable: false, blank: false)
			startTime(nullable: false, validator: {val, obj ->
				if (val > obj.endTime)
					return 'startTimeAfterEndTime.message'
			})
			endTime(nullable: false, validator: {val, obj ->
				if (val < obj.startTime)
					return 'endTimeBeforeStartTime.message'
			})
			startBid(nullable: false)
			hiddenMinBid(nullable: true)
			name(nullable: false)
			description(nullable: false)
			category(nullable: false)
			image(nullable: true)
			isbn (nullable: true, validator: {
				if (it == null)
					return true

				def pattern
				it = it.replaceAll("-", "")
				if (it.size() == 13) {
					pattern = ~/(?=.{13}$)97(?:8|9)\d\d\d\d\d\d\d\d\d\d$/
					if (!pattern.matcher(it).matches())
						return 'isbnError';
				}
				else if (it.size() == 10) {
					pattern = ~/(?=.{10}$)97(?:8|9)\d\d\d\d\d\d\d$/
					if (!pattern.matcher(it).matches())
						return 'isbnError';
				}
			})
			weight(nullable: true)
			dimension(nullable: true)
			quantity(min: 1, nullable: true)
		}
	}
}